/*
 * Copyright (C) 2013 Michael
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
package com.jm.jmsql.sql;

import com.jm.commons.components.editor.JMEditorPane;
import com.jm.jmsql.models.SQLPredictionsListModel;
import com.jm.jmsql.objects.Definition;
import com.jm.jmsql.objects.Schema;
import com.jm.jmsql.objects.base.JMSqlObject;
import com.jm.jmsql.objects.base.Library;
import com.jm.jmsql.sql.predictions.events.PredictionAdapter;
import com.jm.jmsql.sql.predictions.events.PredictionEvent;
import com.jm.jmsql.sql.predictions.events.PredictionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.EventListener;
import java.util.List;
import javax.swing.event.EventListenerList;

/**
 * 
 * @author Michael L.R. Marques
 */
public class SQLPredictions extends javax.swing.JDialog {
    
    //
    private EventListenerList listeners = new EventListenerList();
    
    /**
     * Creates new form SQLPredictions
     * @param codeEditor
     */
    public SQLPredictions(final JMEditorPane codeEditor) {
        initComponents();
        this.lstPredictions.setCellRenderer(new SQLPredictionsListModel.SQLPredictionsCellRenderer());
        this.lstPredictions.setModel(new SQLPredictionsListModel(new ArrayList(0)));
        this.lstPredictions.addKeyListener(new KeyAdapter() {
            @Override
            public void keyReleased(KeyEvent e) {
                if (KeyEvent.VK_ENTER == e.getKeyCode()) {
                    firePredictionSelected(((SQLPredictionsListModel) lstPredictions.getModel()).getList(), lstPredictions.getSelectedIndex());
                }
            }
        });
        this.lstPredictions.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                if (MouseEvent.BUTTON1 == e.getButton() &&
                        e.getClickCount() == 2) {
                    firePredictionSelected(((SQLPredictionsListModel) lstPredictions.getModel()).getList(), lstPredictions.getSelectedIndex());
                }
            }
        });
        addPredictionListener(new PredictionAdapter() {
            @Override
            public void predictionSelected(PredictionEvent e) {
                setVisible(false);
            }
        });
    }
    
    /**
     * 
     * @param editor
     * @param definition 
     */
    public void predict(final JMEditorPane editor, final Definition definition) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                firePredicting();
                String current = "";
                for (int i = editor.getCaretPosition(); i >= 0; i--) {
                    char character = editor.getText().charAt(i);
                    if (Character.isWhitespace(character)) {
                        break;
                    }
                    current = character + current;
                }
                lstPredictions.setModel(new SQLPredictionsListModel(buildPredictionList(current.split("[.]"), definition)));
                pack();
                firePredicted(((SQLPredictionsListModel) lstPredictions.getModel()).getList());
            }
        }).start();
    }
    
    /**
     * 
     * @param prediction
     * @return 
     */
    private List<JMSqlObject> buildPredictionList(String[] prediction, Definition definition) {
        List<JMSqlObject> predictions = new ArrayList();
        if (prediction.length == 0) {
            if (definition.isLibrary()) {
                for (JMSqlObject lib : definition) {
                    predictions.addAll(lib);
                }
            } else {
                predictions.addAll(definition);
            }
        } else if (prediction.length == 1) {
            if (definition.isLibrary()) {
                for (JMSqlObject lib : definition) {
                    for (JMSqlObject obj : lib) {
                        if (obj.getName().contains(prediction[0])) {
                            predictions.add(obj);
                        }
                    }
                }
            } else {
                for (JMSqlObject lib : definition) {
                    if (lib.getName().contains(prediction[0])) {
                        predictions.add(lib);
                    }
                }
                if (predictions.size() == 1 &&
                        predictions.get(0).getName().equalsIgnoreCase(prediction[0])) {
                    Schema schema = (Schema) predictions.get(0);
                    predictions.clear();
                    for (JMSqlObject object : schema.getTables()) {
                        predictions.add(object);
                    }
                } else if (predictions.isEmpty()) {
                    for (JMSqlObject lib : definition) {
                        for (JMSqlObject obj : lib) {
                            for (JMSqlObject obj2 : obj) {
                                if (obj2.getName().contains(prediction[0])) {
                                    predictions.add(obj2);
                                }
                            }
                        }
                    }
                }
            }
        } else if (prediction.length == 2) {
            if (definition.isLibrary()) {
                for (JMSqlObject obj : definition) {
                    for (JMSqlObject obj2 : obj) {
                        if (obj2.getName().contains(prediction[0]) ||
                                obj2.getName().contains(prediction[1])) {
                            predictions.add(obj2);
                        }
                    }
                }
            } else {
                Library library = null;
                for (JMSqlObject lib : definition) {
                    if (lib.getName().equalsIgnoreCase(prediction[0])) {
                        library = (Library) lib;
                        break;
                    }
                }
                if (library != null) {
                    for (JMSqlObject object : (JMSqlObject) library) {
                        for (JMSqlObject obj : object) {
                            if (obj.getName().contains(prediction[1])) {
                                predictions.add(obj);
                            }
                        }
                    }
                }
            }
        } else if (prediction.length == 3) {
            Library library = null;
            for (JMSqlObject lib : definition) {
                if (lib.getName().equalsIgnoreCase(prediction[0])) {
                    library = (Library) lib;
                    break;
                }
            }
            if (library != null) {
                JMSqlObject object = null;
                for (JMSqlObject obj : (JMSqlObject) library) {
                    for (JMSqlObject obj2 : obj) {
                        if (obj2.getName().equalsIgnoreCase(prediction[1])) {
                            object = obj2;
                            break;
                        }
                    }
                }
                if (object != null) {
                    for (JMSqlObject obj : object) {
                        if (obj.getName().contains(prediction[2])) {
                            predictions.add(obj);
                        }
                    }
                }
            }
        }
        return predictions;
    }
    
    /**
     * Registers PredictionListener
     * @param listener 
     */
    public void addPredictionListener(PredictionListener listener) {
        this.listeners.add(PredictionListener.class, listener);
    }
    
    /**
     * De-registers PredictionListener
     * @param listener 
     */
    public void removePredictionListener(PredictionListener listener) {
        this.listeners.remove(PredictionListener.class, listener);
    }
    
    /**
     * 
     */
    public void firePredicting() {
        for (EventListener listener : this.listeners.getListeners(PredictionListener.class)) {
            ((PredictionListener) listener).predicting(new PredictionEvent());
        }
    }
    
    /**
     * 
     * @param predictionList 
     */
    public void firePredicted(List<JMSqlObject> predictionList) {
        for (EventListener listener : this.listeners.getListeners(PredictionListener.class)) {
            ((PredictionListener) listener).predicted(new PredictionEvent(predictionList));
        }
    }
    
    /**
     * 
     * @param predictionList
     * @param index 
     */
    public void firePredictionSelected(List<JMSqlObject> predictionList, int index) {
        for (EventListener listener : this.listeners.getListeners(PredictionListener.class)) {
            ((PredictionListener) listener).predictionSelected(new PredictionEvent(predictionList, index));
        }
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jPanel1 = new javax.swing.JPanel();
        jScrollPane1 = new javax.swing.JScrollPane();
        lstPredictions = new javax.swing.JList();

        setAlwaysOnTop(true);
        setAutoRequestFocus(false);
        setUndecorated(true);
        setResizable(false);
        addWindowFocusListener(new java.awt.event.WindowFocusListener() {
            public void windowGainedFocus(java.awt.event.WindowEvent evt) {
            }
            public void windowLostFocus(java.awt.event.WindowEvent evt) {
                loseFocus(evt);
            }
        });

        jScrollPane1.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
        jScrollPane1.setRequestFocusEnabled(false);

        lstPredictions.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
        lstPredictions.setToolTipText("");
        jScrollPane1.setViewportView(lstPredictions);

        javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
        jPanel1.setLayout(jPanel1Layout);
        jPanel1Layout.setHorizontalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 345, Short.MAX_VALUE)
        );
        jPanel1Layout.setVerticalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 216, Short.MAX_VALUE)
        );

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents

    private void loseFocus(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_loseFocus
        //setVisible(false);
    }//GEN-LAST:event_loseFocus

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JPanel jPanel1;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JList lstPredictions;
    // End of variables declaration//GEN-END:variables
}
